# -*-coding:utf-8-*-
# 导入 paho-mqtt 的 Client：
import time
import paho.mqtt.client as mqtt
import json
from io import BytesIO

from utility.firepark_time import local_time_str
import datetime
import os

import cv2
import numpy as np
from PIL import Image

# Create your views here.

from tensorflow import keras

from apps.User.CNN import cnn_predict
from apps.User.Unet import unet_predict
from apps.User.core import locate_and_correct
from firepark_admin.models import Plate, Userinfo, use_records, Spaces, all_records, no_register_records
from firepark_park.park import get_fee
from utility.firepark_time import get_datetime_mysql

unacked_sub = []  # 未获得服务器响应的订阅消息 id 列表
park_ids = []
temp_file_name = '1001.jpg'
pic_path = r'F:\firepark\media'
plate_numbers = []


def set_allow_payload(available=0, fee=0, status=0, is_register=0):
    allow_payload = {}
    allow_payload['available'] = available
    allow_payload['fee'] = fee
    allow_payload['status'] = status
    allow_payload['is_register'] = is_register
    return json.dumps(allow_payload)

# 用于响应服务器端 CONNACK 的 callback，如果连接正常建立，rc 值为 0
def on_connect(client, userdata, flags, rc):
    print("Connection returned with result code:" + str(rc))
    # 订阅单个主题
    result, mid = client.subscribe("pic", 0)
    unacked_sub.append(mid)
    result, mid = client.subscribe("park_id", 0)
    unacked_sub.append(mid)


# 用于响应服务器端 PUBLISH 消息的 callback，打印消息主题和内容
def on_message(client, userdata, msg):
    if msg.topic == 'pic':
        image = msg.payload
        # covert byte to RGB image
        img = Image.open(BytesIO(image))
        img.save(pic_path + '\\' + temp_file_name)
        print("Received message, topic:" + msg.topic)

        unet = keras.models.load_model('apps/User/unet.h5')
        cnn = keras.models.load_model('apps/User/cnn.h5')
        cnn_predict(cnn, [np.zeros((80, 240, 3))])
        img_src_path = "media/%s" % temp_file_name
        img_open = Image.open(img_src_path)
        if img_open.size[0] * img_open.size[1] > 240 * 80:
            img_open = img_open.resize((512, 512), Image.ANTIALIAS)
        img_src = cv2.imdecode(np.fromfile(img_src_path, dtype=np.uint8), -1)  # 从中文路径读取时用
        h, w = img_src.shape[0], img_src.shape[1]
        if h * w <= 240 * 80 and 2 <= w / h <= 5:  # 满足该条件说明可能整个图片就是一张车牌,无需定位,直接识别即可
            lic = cv2.resize(img_src, dsize=(240, 80), interpolation=cv2.INTER_AREA)[:, :, :3]  # 直接resize为(240,80)
            img_src_copy, Lic_img = img_src, [lic]
        else:  # 否则就需通过unet对img_src原图预测,得到img_mask,实现车牌定位,然后进行识别
            img_src, img_mask = unet_predict(unet, img_src_path)
            img_src_copy, Lic_img = locate_and_correct(img_src, img_mask)

        Lic_pred = cnn_predict(cnn, Lic_img)  # 利用cnn进行车牌的识别预测,Lic_pred中存的是元祖(车牌图片,识别结果)

        if Lic_pred:
            img = Image.fromarray(img_src_copy[:, :, ::-1])  # i
            for i, lic_pred in enumerate(Lic_pred):
                print(i, lic_pred[1])
                plate_numbers.append(lic_pred[1])
                message = "车牌号是" + lic_pred[1]
                print(message)

    elif msg.topic == 'park_id':
        park_id = int(msg.payload)
        park_ids.append(park_id)
        print("Received message, topic:" + msg.topic + " payload:" + str(msg.payload))
        if len(park_ids) > 0 and len(plate_numbers) > 0:
            parking_handle(client, park_ids, plate_numbers)


def parking_handle(client, park_ids, plate_numbers):
    length = len(plate_numbers)
    for i in range(0, length):
        # allow payload
        available = 1
        fee = 0
        park_id = park_ids[i]
        plate_number = plate_numbers[i]
        park_ids.pop(i)
        plate_numbers.pop(i)
        now_time = get_datetime_mysql()
        if Plate.objects.filter(plate_number=plate_number).exists():
            print('有这个车')
            is_register = 1
            user = Plate.objects.filter(plate_number=plate_number).first().users
            s = Userinfo.objects.filter(token=user.tokens).first()
            counts = use_records.objects.filter(user=s, plate_number=plate_number, park_id=park_id).count()
            space = Spaces.objects.get(park_id__exact=park_id)
            if counts % 2 == 0:
                # 入库 status=0
                status = 0
                if space.shengyu <= 0:
                    available = 0
                    allow_payload = set_allow_payload(available, fee, status, is_register)
                    client.publish('allow', payload=allow_payload)
                    continue
                use_records.objects.create(user=s,
                                           plate_number=plate_number,
                                           status="ru",
                                           add_time=now_time,
                                           park_id=park_id,
                                           ).save()

                space.shengyu -= 1
                space.save()
            else:
                # 出库status为1
                status = 1
                ur = use_records.objects.filter(user=s, plate_number=plate_number, park_id=park_id)[0]
                in_time = str(ur.add_time)
                in_time = datetime.datetime.strptime(in_time, '%Y-%m-%d %H:%M:%S')
                fee = get_fee(in_time, now_time, s.vip_status)

                all_records.objects.create(plate_number=plate_number,
                                           in_time=ur.add_time,
                                           out_time=now_time,
                                           park_id=park_id,
                                           pay=fee).save()

                use_records.objects.create(user=s,
                                           plate_number=plate_number,
                                           status="chu",
                                           add_time=now_time,
                                           park_id=park_id,
                                           ).save()
                s.balance -= fee
                s.save()
                if s.balance < 5:
                    # 欠费处理
                    status = 2
                space.shengyu += 1
                space.save()
            allow_payload = set_allow_payload(available, fee, status, is_register)
            client.publish('allow', payload=allow_payload)
        else:
            # 没有注册的车
            is_register = 0
            counts = no_register_records.objects.filter(plate_number=plate_number, park_id=park_id).count()
            space = Spaces.objects.get(park_id__exact=park_id)
            available = 1
            if counts % 2 == 0:
                # 入库 status=0
                status = 0
                if space.shengyu <= 0:
                    available = 0
                    allow_payload = set_allow_payload(available, fee, status, is_register)
                    client.publish('allow', payload=allow_payload)
                    continue
                no_register_records.objects.create(plate_number=plate_number,
                                                   status="ru",
                                                   add_time=now_time,
                                                   park_id=park_id,
                                                   ).save()

                space.shengyu -= 1
                space.save()
            else:
                # 出库status为1
                status = 1
                ur = no_register_records.objects.filter(plate_number=plate_number, park_id=park_id)[0]
                in_time = str(ur.add_time)
                in_time = datetime.datetime.strptime(in_time, '%Y-%m-%d %H:%M:%S')
                fee = get_fee(in_time, now_time, 0)

                all_records.objects.create(plate_number=plate_number,
                                           in_time=ur.add_time,
                                           out_time=now_time,
                                           park_id=park_id,
                                           pay=fee).save()

                no_register_records.objects.create(plate_number=plate_number,
                                                   status="chu",
                                                   add_time=now_time,
                                                   park_id=park_id,
                                                   ).save()

                space.shengyu += 1
                space.save()
            allow_payload = set_allow_payload(available, fee, status, is_register)
            client.publish('allow', payload=allow_payload)


# 在连接断开时的 callback，打印 result code
def on_disconnect(client, userdata, rc):
    print("Disconnection returned result:" + str(rc))


# 在订阅获得服务器响应后，从为响应列表中删除该消息 id
def on_subscribe(client, userdata, mid, granted_qos):
    print("on_subscibe ok")
    unacked_sub.remove(mid)


def mqtt_loop():
    client_id = local_time_str()
    # 构造一个 Client 实例
    client = mqtt.Client(client_id=client_id)
    client.on_connect = on_connect
    client.on_disconnect = on_disconnect
    client.on_message = on_message
    client.on_subscribe = on_subscribe
    # 连接 broker
    # connect() 函数是阻塞的，在连接成功或失败后返回。如果想使用异步非阻塞方式，可以使用 connect_async() 函数。
    client.connect("127.0.0.1", 1883, 60)
    client.loop_start()

    while len(unacked_sub) != 0:
        time.sleep(1)

    # client.publish("pic", payload=pic_payload)

    # 断开连接
    time.sleep(3600)  # 等待消息处理结束
    # client.loop_stop()
    # client.disconnect()
    print(park_ids)
    return park_ids, temp_file_name



